{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ic4_occAAiAT"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "ioaprt5q5US7"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "yCl0eTNH5RS3"
      },
      "outputs": [],
      "source": [
        "#@title MIT License\n",
        "#\n",
        "# Copyright (c) 2017 François Chollet\n",
        "#\n",
        "# Permission is hereby granted, free of charge, to any person obtaining a\n",
        "# copy of this software and associated documentation files (the \"Software\"),\n",
        "# to deal in the Software without restriction, including without limitation\n",
        "# the rights to use, copy, modify, merge, publish, distribute, sublicense,\n",
        "# and/or sell copies of the Software, and to permit persons to whom the\n",
        "# Software is furnished to do so, subject to the following conditions:\n",
        "#\n",
        "# The above copyright notice and this permission notice shall be included in\n",
        "# all copies or substantial portions of the Software.\n",
        "#\n",
        "# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n",
        "# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n",
        "# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL\n",
        "# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n",
        "# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n",
        "# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n",
        "# DEALINGS IN THE SOFTWARE."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ItXfxkxvosLH"
      },
      "source": [
        "# TensorFlow Hub によるテキストの分類: 映画レビュー"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hKY4XMc9o8iB"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/keras/text_classification_with_hub\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org で表示</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/tutorials/keras/text_classification_with_hub.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab で実行</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/tutorials/keras/text_classification_with_hub.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub でソースを表示</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/tutorials/keras/text_classification_with_hub.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">ノートブックをダウンロード</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Eg62Pmz3o83v"
      },
      "source": [
        "このノートブックでは、映画レビューのテキストを使用して、レビューを*肯定的評価*と*否定的評価*に分類します。これは、機械学習の問題で広く適用されている、重要な分類手法である*二項*分類の例です。\n",
        "\n",
        "このチュートリアルでは、TensorFlow Hub と Keras を使用した変換学習の基本アプリケーションを実演します。\n",
        "\n",
        "[Internet Movie Database](https://www.imdb.com/) より、50,000 件の映画レビューテキストが含まれる [IMDB データセット](https://www.tensorflow.org/api_docs/python/tf/keras/datasets/imdb)を使用します。これｒは、トレーニング用の 25,000 件のレビューとテスト用の 25,000 件のレビューに分割されます。トレーニングセットとテストセットは*均衡が保たれており*、肯定的評価と否定的評価が同じ割合で含まれます。\n",
        "\n",
        "このノートブックでは、TensorFlow でモデルを構築してトレーニングするための [tf.keras](https://www.tensorflow.org/guide/keras) という高レベル API と、変換学習用のライブラリ兼プラットフォームである [TensorFlow Hub](https://www.tensorflow.org/hub) を使用します。`tf.keras` を使用した、より高度なテキスト分類チュートリアルについては、[MLCC Text Classification Guide](https://developers.google.com/machine-learning/guides/text-classification/) をご覧ください。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2ew7HTbPpCJH"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "\n",
        "import tensorflow as tf\n",
        "\n",
        "!pip install tensorflow-hub\n",
        "!pip install tfds-nightly\n",
        "import tensorflow_hub as hub\n",
        "import tensorflow_datasets as tfds\n",
        "\n",
        "print(\"Version: \", tf.__version__)\n",
        "print(\"Eager mode: \", tf.executing_eagerly())\n",
        "print(\"Hub version: \", hub.__version__)\n",
        "print(\"GPU is\", \"available\" if tf.config.experimental.list_physical_devices(\"GPU\") else \"NOT AVAILABLE\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iAsKG535pHep"
      },
      "source": [
        "## IMDB データセットをダウンロードする\n",
        "\n",
        "IMDB データセットは、[imdb reviews](https://www.tensorflow.org/datasets/catalog/imdb_reviews) または [TensorFlow データセット](https://www.tensorflow.org/datasets)で提供されています。次のコードを使って、IMDB データセットをマシン（または Colab ランタイム）にダウンロードしてください。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zXXx5Oc3pOmN"
      },
      "outputs": [],
      "source": [
        "# Split the training set into 60% and 40%, so we'll end up with 15,000 examples\n",
        "# for training, 10,000 examples for validation and 25,000 examples for testing.\n",
        "train_data, validation_data, test_data = tfds.load(\n",
        "    name=\"imdb_reviews\", \n",
        "    split=('train[:60%]', 'train[60%:]', 'test'),\n",
        "    as_supervised=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "l50X3GfjpU4r"
      },
      "source": [
        "## データを確認する\n",
        "\n",
        "データの形式を確認してみましょう。各サンプルは、映画レビューを表す文章と対応するラベルです。文章はまったく事前処理されていません。ラベルは 0 または 1 の整数値で、0 は否定的評価で 1 は肯定的評価を示します。\n",
        "\n",
        "最初の 10 個のサンプルを出力しましょう。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "QtTS4kpEpjbi"
      },
      "outputs": [],
      "source": [
        "train_examples_batch, train_labels_batch = next(iter(train_data.batch(10)))\n",
        "train_examples_batch"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IFtaCHTdc-GY"
      },
      "source": [
        "最初の 10 個のラベルも出力しましょう。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tvAjVXOWc6Mj"
      },
      "outputs": [],
      "source": [
        "train_labels_batch"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LLC02j2g-llC"
      },
      "source": [
        "## モデルを構築する\n",
        "\n",
        "ニューラルネットワークは、レイヤーのスタックによって作成されています。これには、次の 3 つのアーキテクチャ上の決定が必要です。\n",
        "\n",
        "- どのようにテキストを表現するか。\n",
        "- モデルにはいくつのレイヤーを使用するか。\n",
        "- 各レイヤーにはいくつの*非表示ユニット*を使用するか。\n",
        "\n",
        "この例では、入力データは文章で構成されています。予測するラベルは、0 または 1 です。\n",
        "\n",
        "テキストの表現方法としては、文章を埋め込みベクトルに変換する方法があります。トレーニング済みのテキスト埋め込みを最初のレイヤーとして使用することで、次のような 3 つのメリットを得ることができます。\n",
        "\n",
        "- テキストの事前処理を心配する必要がない。\n",
        "- 変換学習を利用できる。\n",
        "- 埋め込みのサイズは固定されているため、処理しやすい。\n",
        "\n",
        "この例では、[google/tf2-preview/gnews-swivel-20dim/1](https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1) という、[TensorFlow Hub](https://www.tensorflow.org/hub) の **トレーニング済みのテキスト埋め込みモデル** を使用します。\n",
        "\n",
        "このチュートリアルのためにテストできるトレーニング済みモデルが、ほかに 3 つあります。\n",
        "\n",
        "- [google/tf2-preview/gnews-swivel-20dim-with-oov/1](https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim-with-oov/1) - [google/tf2-preview/gnews-swivel-20dim/1](https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1) と同じものですが、2.5% の語彙が OOV バケットに変換されています。これは、タスクの語彙とモデルの語彙が完全に重複しない場合に役立ちます。\n",
        "- [google/tf2-preview/nnlm-en-dim50/1](https://tfhub.dev/google/tf2-preview/nnlm-en-dim50/1) - 最大 100 万語彙サイズと 50 次元の大規模なモデルです。\n",
        "- [google/tf2-preview/nnlm-en-dim128/1](https://tfhub.dev/google/tf2-preview/nnlm-en-dim128/1) - 最大 100 万語彙サイズと 128 次元のさらに大規模なモデルです。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "In2nDpTLkgKa"
      },
      "source": [
        "では始めに、TensorFlow Hub モデル を使用して文章を埋め込む Keras レイヤーを作成し、いくつかの入力サンプルで試してみましょう。入力テキストの長さに関係なく、埋め込みの出力形状は、`(num_examples, embedding_dimension)` であるところに注意してください。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_NUbzVeYkgcO"
      },
      "outputs": [],
      "source": [
        "embedding = \"https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1\"\n",
        "hub_layer = hub.KerasLayer(embedding, input_shape=[], \n",
        "                           dtype=tf.string, trainable=True)\n",
        "hub_layer(train_examples_batch[:3])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dfSbV6igl1EH"
      },
      "source": [
        "今度は、完全なモデルを構築しましょう。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "xpKOoWgu-llD"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential()\n",
        "model.add(hub_layer)\n",
        "model.add(tf.keras.layers.Dense(16, activation='relu'))\n",
        "model.add(tf.keras.layers.Dense(1))\n",
        "\n",
        "model.summary()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6PbKQ6mucuKL"
      },
      "source": [
        "レイヤーは順にスタックされて、分類器が構築されます。\n",
        "\n",
        "1. 最初のレイヤーは、TensorFlow Hub レイヤーです。このレイヤーは文章から埋め込みベクトルにマッピングするために、トレーニング済みの SavedModel を使用します。使用中のトレーニング済みのテキスト埋め込みモデル（[google/tf2-preview/gnews-swivel-20dim/1](https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1)）は文章をトークンに分割し、各トークンを埋め込んで、埋め込みを組み合わせます。その結果、次元は `(num_examples, embedding_dimension)` となります。\n",
        "2. この固定長の出力ベクトルは、16 個の非表示ユニットを持つ完全に接続された（`Dense`）レイヤーを介してパイプ処理されます。\n",
        "3. 最後のレイヤーは、単一の出力ノードと密に接続されています。\n",
        "\n",
        "モデルをコンパイルしましょう。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "L4EqVWg4-llM"
      },
      "source": [
        "### 損失関数とオプティマイザ\n",
        "\n",
        "モデルをトレーニングするには、損失関数とオプティマイザが必要です。これは二項分類問題であり、モデルはロジット（線形アクティベーションを持つ単一ユニットレイヤー）を出力するため、`binary_crossentropy` 損失関数を使用します。\n",
        "\n",
        "これは、損失関数の唯一の選択肢ではありませんが、たとえば、 `mean_squared_error` を使用することもできます。ただし、一般的には、確率を扱うには `binary_crossentropy` の方が適しているといえます。これは、確率分布間、またはこのケースではグランドトゥルース分布と予測間の「距離」を測定するためです。\n",
        "\n",
        "後の方で、回帰問題（家の価格を予測するなど）を考察する際に、平均二乗誤差と呼ばれる別の損失関数の使用方法を確認します。\n",
        "\n",
        "では、オプティマイザと損失関数を使用するようにモデルを構成します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Mr0GP-cQ-llN"
      },
      "outputs": [],
      "source": [
        "model.compile(optimizer='adam',\n",
        "              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),\n",
        "              metrics=['accuracy'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "35jv_fzP-llU"
      },
      "source": [
        "## モデルをトレーニングする\n",
        "\n",
        "モデルを 512 サンプルのミニバッチで 20 エポック、トレーニングします。これは、`x_train` と `y_train` テンソルのすべてのサンプルを 20 回イテレーションします。トレーニング中、検証セットの 10,000 個のサンプルで、モデルの損失と精度を監視します。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "tXSGrjWZ-llW"
      },
      "outputs": [],
      "source": [
        "history = model.fit(train_data.shuffle(10000).batch(512),\n",
        "                    epochs=20,\n",
        "                    validation_data=validation_data.batch(512),\n",
        "                    verbose=1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9EEGuDVuzb5r"
      },
      "source": [
        "## モデルを評価する\n",
        "\n",
        "モデルがどのように実行するか見てみましょう。2 つの値が返されます。損失（誤差、値が低いほど良）と精度です。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zOMKywn4zReN"
      },
      "outputs": [],
      "source": [
        "results = model.evaluate(test_data.batch(512), verbose=2)\n",
        "\n",
        "for name, value in zip(model.metrics_names, results):\n",
        "  print(\"%s: %.3f\" % (name, value))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "z1iEXVTR0Z2t"
      },
      "source": [
        "このかなり単純なアプローチで、約 87％ の精度が達成されます。より高度なアプローチを使えば、95％ に近づくでしょう。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5KggXVeL-llZ"
      },
      "source": [
        "## 参考資料\n",
        "\n",
        "文字列入力を使ったより一般的な操作方法やトレーニング中の精度と損失の進捗に関するより詳細な分析については、[事前処理済みのテキストを使用したテキスト分類](./text_classification.ipynb)チュートリアルをご覧ください。"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "text_classification_with_hub.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
